package com.bdqn.easybuy1.dao;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * 对数据库的通用操作，包括
 * ①、通用增、删、改操作
 * ②、通用查询——单个对象
 * ③、通用查询——对象列表
 * ④、通用查询单个值
 * ⑤、所有通用操作支持事务操作
 */
public abstract class BaseDao<T> {
    /**
     * 最数据库进行的通用操作的封装类
     */
    private QueryRunner queryRunner = new QueryRunner();

    /**
     * 定义一个变量来接收泛型的类型
     */
    private Class<T> type;

    /**
     * 获取T的Class对象，获取泛型的类型，
     * 泛型是在被子类继承时才确定的
     */
    public BaseDao() {
        // 获取子类的类型
        Class clazz = this.getClass();

        // 获取父类的类型
        // getGenericSuperclass()方法用来获取当前类的父类的类型
        // ParameterizedType表示的是带泛型的类型
        ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();

        // 获取具体的泛型类型：getActualTypeArguments()获取具体的泛型的类型
        // 这个方法会返回一个Type的数组
        Type[] types = parameterizedType.getActualTypeArguments();

        // 获取具体的泛型类型
        this.type = (Class<T>) types[0];
    }

    /**
     * 通用的增删改操作
     *
     * @param conn   数据库连接
     * @param sql    要执行的SQL语句
     * @param params SQL语句的参数
     * @return 返回数据库受影响的行数
     */
    public int update(Connection conn, String sql, Object... params) {
        int count = 0;
        try {
            count = queryRunner.update(conn, sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return count;
    }

    /**
     * 插入一条数据，同时返回值是它的id；
     * @param conn
     * @param sql
     * @param params
     * @param <T>
     * @return
     */
    public <T> T insert(Connection conn, String sql, Object... params) {
        T t = null;
        try {
            t = queryRunner.insert(conn, sql, new ScalarHandler<T>(), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 获取一个对象
     *
     * @param conn   数据库连接
     * @param sql    要执行的SQL语句
     * @param params SQL语句的参数
     * @return 返回一个T类型的对象
     */
    public T getBean(Connection conn, String sql, Object... params) {
        T t = null;
        try {
            t = queryRunner.query(conn, sql, new BeanHandler<T>(type), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 按照条件获取对象列表
     *
     * @param conn   数据库连接
     * @param sql    要执行的SQL语句
     * @param params SQL语句的参数
     * @return 返回T类型的对象集合
     */
    public List<T> getBeanList(Connection conn, String sql, Object... params) {
        List<T> list = null;
        try {
            list = queryRunner.query(conn, sql, new BeanListHandler<T>(type), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取一个单一值的方法
     *
     * @param conn   数据库连接
     * @param sql    要执行的SQL语句
     * @param params SQL语句的参数
     * @param <E>    方法的返回值类型
     * @return
     */
    public <E> E getValue(Connection conn, String sql, Object... params) {
        E e = null;
        try {
            e = queryRunner.query(conn, sql, new ScalarHandler<E>(), params);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        return e;
    }
}
